package com.example.opengl.egl

import android.graphics.SurfaceTexture
import android.opengl.EGL14
import android.opengl.EGLConfig
import android.opengl.EGLContext
import android.opengl.EGLExt
import android.opengl.EGLSurface
import android.view.Surface


class EGLCore {
    private val FLAG_RECORDABLE = 0x01

    private val EGL_RECORDABLE_ANDROID = 0x3142

    /**
     * EGL相关变量
     */
    /**
     * 显示设备
     */
    private var mEGLDisplay = EGL14.EGL_NO_DISPLAY

    /**
     * 共享上下文 context
     */
    private var mEGLContext = EGL14.EGL_NO_CONTEXT

    /**
     * 基本配置
     */
    private var mEGLConfig: EGLConfig? = null

    /**
     * 初始化上下文
     */
    fun init(eglContext: EGLContext?,flag:Int){
        if (mEGLDisplay !==EGL14.EGL_NO_DISPLAY){
            throw RuntimeException("EGL already set up")
        }
        val shareEGLContext = eglContext?:EGL14.EGL_NO_CONTEXT
        //获取可用的显示窗口
        mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY)
        if (mEGLDisplay == EGL14.EGL_NO_DISPLAY){
            throw RuntimeException("Unable to get EGL14 display")
        }
        val version = IntArray(2)
        //初始化EGL
        if (!EGL14.eglInitialize(mEGLDisplay,version,0,version,1)){
            mEGLDisplay = EGL14.EGL_NO_DISPLAY
            throw RuntimeException("unable to initialize EGL14")
        }
        if (mEGLContext == EGL14.EGL_NO_CONTEXT){
            val config = getConfig(flag,2)?:throw  RuntimeException("Unable to find a suitable EGLConfig")
            val attr2List = intArrayOf(EGL14.EGL_CONTEXT_CLIENT_VERSION,2,EGL14.EGL_NONE)
            //创建一个渲染上下文
            val context = EGL14.eglCreateContext(mEGLDisplay,config,shareEGLContext,attr2List,0)
            mEGLConfig = config
            mEGLContext = context
        }


    }

    /**
     * 获取EGL配置信息
     */
    private fun getConfig(flags: Int, version: Int): EGLConfig? {
        var renderType = EGL14.EGL_OPENGL_ES2_BIT
        if (version >=3){
            // 配置EGL 3
            renderType = renderType or EGLExt.EGL_OPENGL_ES3_BIT_KHR
        }
        //定义configs匹配的属性列表
        val attrList = intArrayOf(
            EGL14.EGL_RED_SIZE, 8,
            EGL14.EGL_GREEN_SIZE, 8,
            EGL14.EGL_BLUE_SIZE, 8,
            EGL14.EGL_ALPHA_SIZE, 8,
            //EGL14.EGL_DEPTH_SIZE, 16,
            //EGL14.EGL_STENCIL_SIZE, 8,
            EGL14.EGL_RENDERABLE_TYPE, renderType,
            EGL14.EGL_NONE, 0, // placeholder for recordable [@-3]
            EGL14.EGL_NONE
        )
        //配置Android指定的标记
        if (flags and FLAG_RECORDABLE != 0) {
            attrList[attrList.size - 3] = EGL_RECORDABLE_ANDROID
            attrList[attrList.size - 2] = 1
        }
        val configs = arrayOfNulls<EGLConfig>(1) //指定配置列表
        val numConfigs = IntArray(1)//指定返回配置大小

        //获取EGL配置
        if (!EGL14.eglChooseConfig(mEGLDisplay, attrList, 0,
                configs, 0, configs.size,
                numConfigs, 0)) {
            return null
        }
        //使用系统推荐的第一个配置
        return configs[0]
    }

    /**
     * 创建可显示的surface  EGL窗口
     */
    fun createWindowSurface(surface: Any): EGLSurface {
        if (surface !is Surface && surface !is SurfaceTexture) {
            throw RuntimeException("Invalid surface: $surface")
        }
        val surfaceAttr = intArrayOf(EGL14.EGL_NONE)
        // 1 指定EGL显示链接. 2 指定配置 3，指定原生窗口，4. 指定窗口属性列表；可能为null
        return EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, surfaceAttr, 0)
    }

    /**
     * 创建离屏渲染缓存
     */
    fun createOffscreenSurface(width: Int, height: Int): EGLSurface {
        val surfaceAttr = intArrayOf(
            EGL14.EGL_WIDTH, width,
            EGL14.EGL_HEIGHT, height,
            EGL14.EGL_NONE
        )

        return EGL14.eglCreatePbufferSurface(
            mEGLDisplay, mEGLConfig,
            surfaceAttr, 0
        ) ?: throw RuntimeException("Surface was null")
    }

    /**
     * 将当前线程与上下文进行绑定
     */
    fun makeCurrent(eglSurface: EGLSurface){
        if (mEGLDisplay === EGL14.EGL_NO_DISPLAY) {
            throw RuntimeException("EGLDisplay is null, call init first")
        }
        if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) {
            throw RuntimeException("makeCurrent(eglSurface) failed")
        }
    }
    /**
     * 将当前线程与上下文进行绑定
     */
    fun makeCurrent(drawSurface: EGLSurface, readSurface: EGLSurface) {
        if (mEGLDisplay === EGL14.EGL_NO_DISPLAY) {
            throw RuntimeException("EGLDisplay is null, call init first")
        }
        if (!EGL14.eglMakeCurrent(mEGLDisplay, drawSurface, readSurface, mEGLContext)) {
            throw RuntimeException("eglMakeCurrent(draw,read) failed")
        }
    }
    /**
     * 将缓存图像数据发送到设备进行显示
     */
    fun swapBuffers(eglSurface: EGLSurface): Boolean {
        return EGL14.eglSwapBuffers(mEGLDisplay, eglSurface)
    }
    /**
     * 设置当前帧的时间
     * 单位:ns
     */
    fun setPresentationTime(eglSurface: EGLSurface,nsecs:Long){
        EGLExt.eglPresentationTimeANDROID(mEGLDisplay,eglSurface,nsecs)
    }
    /**
     * 销毁EglSurface
     */
    fun destroySurface(eglSurface: EGLSurface){
        EGL14.eglMakeCurrent(mEGLDisplay,EGL14.EGL_NO_SURFACE,EGL14.EGL_NO_SURFACE,EGL14.EGL_NO_CONTEXT)
        EGL14.eglDestroySurface(mEGLDisplay,eglSurface)
    }


    /**
     * 释放资源
     */
    fun release() {
        if (mEGLDisplay !== EGL14.EGL_NO_DISPLAY) {
            // Android is unusual in that it uses a reference-counted EGLDisplay.  So for
            // every eglInitialize() we need an eglTerminate().
            EGL14.eglMakeCurrent(
                mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,
                EGL14.EGL_NO_CONTEXT
            )
            EGL14.eglDestroyContext(mEGLDisplay, mEGLContext)
            EGL14.eglReleaseThread()
            EGL14.eglTerminate(mEGLDisplay)
        }

        mEGLDisplay = EGL14.EGL_NO_DISPLAY
        mEGLContext = EGL14.EGL_NO_CONTEXT
        mEGLConfig = null
    }
}